Memcached是什么?
Memcached是由Danga Interactive开发的,高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。
Memcached能缓存什么?
通过在内存里维护一个统一的巨大的hash表,Memcached能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。
Memcached快么?
非常快。Memcached使用了libevent(如果可以的话,在linux下使用epoll)来均衡任何数量的打开链接,使用非阻塞的网络I/O,对内部对象实现引用计数(因此,针对多样的客户端,对象可以处在多样的状态), 使用自己的页块分配器和哈希表, 因此虚拟内存不会产生碎片并且虚拟内存分配的时间复杂度可以保证为O(1).。
Danga Interactive为提升Danga Interactive的速度研发了Memcached。目前,LiveJournal.com每天已经在向一百万用户提供多达两千万次的页面访问。而这些,是由一个由web服务器和数据库服务器组成的集群完成的。Memcached几乎完全放弃了任何数据都从数据库读取的方式,同时,它还缩短了用户查看页面的速度、更好的资源分配方式,以及Memcache失效时对数据库的访问速度。
Memcached的特点
Memcached的缓存是一种分布式的,可以让不同主机上的多个用户同时访问, 因此解决了共享内存只能单机应用的局限,更不会出现使用数据库做类似事情的时候,磁盘开销和阻塞的发生。
Memcached的使用
一 、Memcached服务器端的安装 (此处将其作为系统服务安装)
下载文件:memcached 1.2.1 for Win32 binaries (Dec 23, 2006)
1. 解压缩文件到c:\memcached
2. 命令行输入 'c:\memcached\memcached.exe -d install'
3. 命令行输入 'c:\memcached\memcached.exe -d start' ,该命令启动 Memcached ,默认监听端口为 11211
注:通过 memcached.exe -h 可以查看其帮助
常用设置:
-p <num> 监听的端口
-l <ip_addr> 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u <username> 以<username>的身份运行 (仅在以root运行的时候有效)
-m <num> 最大内存使用,单位MB。默认64MB
-M 内存耗尽时返回错误,而不是删除项
-c <num> 最大同时连接数,默认是1024
-f <factor> 块大小增长因子,默认是1.25
-n <bytes> 最小分配空间,key+value+flags默认是48
-h 显示帮助
C# 下可用的API(每个客户端API中都有详细的说明和注释)
Memcached .NET客户端:
1).NET memcached client library
下载地址:https://sourceforge.net/projects/memcacheddotnet
2)enyim.com Memcached Client
下载地址:https://github.com/enyim/EnyimMemcached/
3)Memcached Providers
下载地址:http://www.codeplex.com/memcachedproviders
注意:直接点击Download按钮会下载一个pdf文档Demo,里面介绍了Memcached Providers,下载此类库需要切换到Download选项卡页面。
4) BeIT Memcached
下载地址:http://code.google.com/p/beitmemcached/
二、 .NET memcached client library
下载文件:https://sourceforge.net/projects/memcacheddotnet/
里面有.Net1.1 和 .Net2.0的两种版本 还有一个不错的例子。
EnyimMemcached https://github.com/enyim/EnyimMemcached/wiki
[代码] Program.cs
using System;
using System.Collections.Generic;
using System.Text;
using Enyim.Caching;
using Enyim.Caching.Memcached;
using System.Net;
using Enyim.Caching.Configuration;
using Membase;
using Membase.Configuration;
using System.Threading;
namespace DemoApp
{
class Program
{
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.Configure();
// or just initialize the client from code
var nscc = new MembaseClientConfiguration();
nscc.SocketPool.ReceiveTimeout = new TimeSpan(0, 0, 2);
nscc.SocketPool.DeadTimeout = new TimeSpan(0, 0, 10);
nscc.Urls.Add(new Uri("http://192.168.2.160:8091/pools/default"));
nscc.Urls.Add(new Uri("http://192.168.2.162:8091/pools/default"));
nscc.Credentials = new NetworkCredential("A", "11111111");
//nscc.BucketPassword = "pass";
ThreadPool.QueueUserWorkItem(o => StressTest(new MembaseClient(nscc, "default"), "TesT_A_"));
//ThreadPool.QueueUserWorkItem(o => StressTest(new MembaseClient(nscc, "default"), "TesT_B_"));
//ThreadPool.QueueUserWorkItem(o => StressTest(new MembaseClient(nscc, "default"), "TesT_C_"));
//ThreadPool.QueueUserWorkItem(o => StressTest(new MembaseClient(nscc, "default"), "TesT_D_"));
Console.ReadLine();
return;
var mcc = new MemcachedClientConfiguration();
mcc.AddServer("192.168.2.200:11211");
mcc.AddServer("192.168.2.202:11211");
mcc.SocketPool.ReceiveTimeout = new TimeSpan(0, 0, 4);
mcc.SocketPool.ConnectionTimeout = new TimeSpan(0, 0, 4);
mcc.SocketPool.DeadTimeout = new TimeSpan(0, 0, 10);
StressTest(new MemcachedClient(mcc), "TesT_");
return;
var nc = new MembaseClient(nscc, "content");
var stats1 = nc.Stats("slabs");
foreach (var kvp in stats1.GetRaw("curr_connections"))
Console.WriteLine("{0} -> {1}", kvp.Key, kvp.Value);
var nc2 = new MembaseClient(nscc, "content");
var stats2 = nc2.Stats();
foreach (var kvp in stats2.GetRaw("curr_connections"))
Console.WriteLine("{0} -> {1}", kvp.Key, kvp.Value);
}
private static void StressTest(MemcachedClient client, string keyPrefix)
{
var i = 0;
var last = true;
var progress = @"-\|/".ToCharArray();
Console.CursorVisible = false;
Dictionary<bool, int> counters = new Dictionary<bool, int>() { { true, 0 }, { false, 0 } };
while (true)
{
var key = keyPrefix + i;
var state = client.Store(StoreMode.Set, key, i) & client.Get<int>(key) == i;
Action updateTitle = () => Console.Title = "Success: " + counters[true] + " Fail: " + counters[false];
if (state != last)
{
Console.ForegroundColor = state ? ConsoleColor.White : ConsoleColor.Red;
Console.Write(".");
counters[state] = 0;
last = state;
updateTitle();
}
else if (i % 200 == 0)
{
//Console.ForegroundColor = state ? ConsoleColor.White : ConsoleColor.Red;
//Console.Write(progress[(i / 200) % 4]);
//if (Console.CursorLeft == 0)
//{
// Console.CursorLeft = Console.WindowWidth - 1;
// Console.CursorTop -= 1;
//}
//else
//{
// Console.CursorLeft -= 1;
//}
updateTitle();
}
i++;
counters[state] = counters[state] + 1;
}
}
}
}
[代码] App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
<sectionGroup name="enyim.com">
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
<section name="log" type="Enyim.Caching.Configuration.LoggerSection, Enyim.Caching" />
</sectionGroup>
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
<section name="northscale" type="Membase.Configuration.MembaseClientSection, Membase" />
<section name="membase" type="Membase.Configuration.MembaseClientSection, Membase" />
</configSections>
<northscale>
<servers bucket="default">
<add uri="http://192.168.2.200:8080/pools/default" />
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" />
<locator type="Enyim.Caching.Memcached.DefaultNodeLocator, Enyim.Caching" />
</northscale>
<membase>
<servers bucket="mc_pass" userName="A" password="11111111" bucketPassword="pass">
<add uri="http://192.168.2.160:8080/pools/default" />
</servers>
<socketPool connectionTimeout="00:00:02" deadTimeout="00:00:10" />
</membase>
<enyim.com>
<log factory="Enyim.Caching.Log4NetFactory, Enyim.Caching.Log4NetAdapter" />
<memcached>
<servers>
<add address="192.168.2.200" port="11211" />
<add address="192.168.2.202" port="11211" />
<add address="192.168.2.204" port="11211" />
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
<!--<authentication type="Enyim.Caching.Memcached.PlainTextAuthenticator, Enyim.Caching" userName="demo" password="demo" />-->
</memcached>
</enyim.com>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c %m%n" />
</layout>
</appender>
<appender name="TraceAppender" type="log4net.Appender.TraceAppender">
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c %m%n" />
</layout>
</appender>
<root>
<level value="Info" />
<appender-ref ref="TraceAppender" />
</root>
<logger name="Enyim.Caching.Memcached.DefaultNodeLocator">
<level value="Debug" />
</logger>
<logger name="Enyim.Caching.Memcached.PooledSocket">
<level value="Info" />
</logger>
<logger name="Enyim.Caching.Memcached.Protocol">
<level value="Info" />
</logger>
<logger name="Membase.VBucketAwareOperationFactory">
<level value="Info" />
</logger>
<logger name="Enyim.Caching.Memcached.MemcachedNode">
<level value="Info" />
</logger>
</log4net>
</configuration>